package com.sky.service.user.impl;
import java.math.BigDecimal;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sky.constant.JwtClaimsConstant;
import com.sky.constant.RedisConstant;
import com.sky.dto.UserLoginDTO;
import com.sky.exception.LoginFailedException;
import com.sky.mapper.admin.DishMapper;
import com.sky.mapper.common.CategoryMapper;
import com.sky.mapper.merchant.MerchantMapper;
import com.sky.mapper.user.UserMapper;
import com.sky.pojo.*;
import com.sky.properties.JwtProperties;
import com.sky.properties.WeChatProperties;
import com.sky.service.common.CategoryService;
import com.sky.service.user.UserService;
import com.sky.utils.JwtUtil;
import com.sky.utils.MapUtils;
import com.sky.vo.DishItemVO;
import com.sky.vo.DishVO;
import com.sky.vo.UserLoginVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @Author:篍
 * @Date: 2025/08/25 14:37
 * @Description:
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService{

    public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private WeChatProperties weChatProperties;

    @Autowired
    private MerchantMapper merchantMapper;

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public UserLoginVO login(UserLoginDTO userLoginDTO) {
        String code = userLoginDTO.getCode();
        String openid = this.getOpenid(code);
        User user = this.lambdaQuery().eq(User::getOpenid, openid).one();
        if (Objects.isNull(user)){
            user=User.builder().openid(openid)
                    .createTime(LocalDateTime.now())
                    .build();
            this.save(user);
        }
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.USER_ID, user.getId());
        String jwt = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
        Merchant merchant = merchantMapper.selectById(1);
        UserLoginVO userLoginVO=new UserLoginVO();
        userLoginVO.setId(user.getId());
        userLoginVO.setOpenid(user.getOpenid());
        userLoginVO.setToken(jwt);
        userLoginVO.setShopName(merchant.getShopName());
        userLoginVO.setShopAddress(merchant.getShopAddress());
        userLoginVO.setShopTelephone(merchant.getShopTelephone());
        //商家地址
        String merchantLngLat = MapUtils.addressToLnglat(merchant.getShopAddress());
        //配送费
        BigDecimal deliveryCost = MapUtils.getDeliveryCost(merchantLngLat, userLoginDTO.getLocation());
        userLoginVO.setDeliveryFee(deliveryCost);
        userLoginVO.setShopId(1L);
        return userLoginVO;
    }

    /**
     * 获取微信用户openid
     * @param code
     * @return
     */
    @Override
    public String getOpenid(String code) {
        Map<String, Object> params= new HashMap<>();
        params.put("appid", weChatProperties.getAppid());
        params.put("secret", weChatProperties.getSecret());
        params.put("js_code", code);
        params.put("grant_type", "authorization_code");
        String responseStr = HttpUtil.get(WX_LOGIN, params);
        JSONObject jsonObject = JSONUtil.parseObj(responseStr);
        if (Objects.nonNull(jsonObject.get("errorCode"))){
            throw new LoginFailedException("微信登录失败"+jsonObject.get("errorMsg"));
        }
        return jsonObject.getStr("openid");
    }

    /**
     * 获取菜品分类列表
     * @return
     */
    @Override
    public List<Category> listCategory() {
        List<Category> categories=new ArrayList<>();
        try {
            categories = (List<Category>) redisTemplate.opsForValue().get(RedisConstant.INDEX_CATEGORY_CACHE);
            if (CollectionUtil.isNotEmpty(categories)){
                return categories;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        categories = categoryMapper.list(null);
        try {
            redisTemplate.opsForValue().set(RedisConstant.INDEX_CATEGORY_CACHE,categories);
        } catch (Exception e) {
            log.error("保存分类缓存失败");
        }
        return categories;
    }

    /**
     * 获取菜品列表
     * @param categoryId
     * @return
     */
    @Override
    public List<DishVO> listDishVo(Long categoryId) {
        List<DishVO> dishVos=new ArrayList<>();
        try {
            dishVos= (List<DishVO>) redisTemplate.opsForValue().get(RedisConstant.INDEX_DISH_CACHE_PREFIX+categoryId);
            if (CollectionUtil.isNotEmpty(dishVos)){
                return dishVos;
            }
        } catch (Exception e) {
            log.error("获取缓存失败{}", e.getMessage());
        }
        dishVos= userMapper.getDishListByCategoryId(categoryId);
        try {
            redisTemplate.opsForValue().set(RedisConstant.INDEX_DISH_CACHE_PREFIX+categoryId,dishVos);
        }catch (Exception e){
            log.error("保存缓存失败{}", e.getMessage());
        }
        return dishVos;
    }
    /**
     * 获取套餐列表
     * @param categoryId
     * @return
     */
    @Override
    public List<Setmeal> listSetmeal(Long categoryId) {
        return userMapper.listSetmeal(categoryId);
    }

    /**
     * 获取套餐内菜品列表
     * @param setmealId
     * @return
     */
    @Override
    public List<DishItemVO> listDishItemVo(Long setmealId) {
        return userMapper.findDishBySetmealId(setmealId);
    }
}
